/**
 * @author denis.onishchenko@gmail.com
 */

package com.prapp.mediag;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import com.feeder.ElementIterator;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

final class Config {

    private static final String T_CONFIG = "config";
    private static final String T_ADDRESS = "address";
    private static final String T_CONTACT = "contact";
    private static final String T_EMAIL = "email";
    private static final String T_FEED = "feed";
    private static final String T_GA = "ga";
    private static final String T_GROUP = "group";
    private static final String T_HTML = "html";
    private static final String T_IMG = "img";
    private static final String T_MAP = "map";
    private static final String T_PHONE = "phone";
    private static final String T_TAB = "tab";
    private static final String T_TABS = "tabs";

    private static final String A_ACCOUNT = "account";
    private static final String A_CC = "cc";
    private static final String A_DATABASE = "database";
    private static final String A_EMAIL = "email";
    private static final String A_ICON = "icon";
    private static final String A_LOGIN = "login";
    private static final String A_NAME = "name";
    private static final String A_NUMBER = "number";
    private static final String A_PASS = "pass";
    private static final String A_SMTP = "smtp";
    private static final String A_SRC = "src";
    private static final String A_SUBJECT = "subject";
    private static final String A_TEXT = "text";
    private static final String A_TO = "to";
    private static final String A_TYPE = "type";
    private static final String A_URL = "url";

    private static final String TAB_CONTACTS = "contacts";
    private static final String TAB_EMAIL = "email";
    private static final String TAB_FEEDS = "feeds";
    private static final String TAB_HTML = "html";

    static Config parse(InputStream in) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document d = db.parse(in);

            if (d == null) return null;

            Element element = ElementIterator.getChildElement(d, T_CONFIG);
            return parse(element);
        }
        catch (Throwable x) {
            throw new RuntimeException(x);
        }
    }

    private static Config parse(Element element) {
        if (element == null) return null;

        Element gaElement = ElementIterator.getChildElement(element, T_GA);
        String ga = gaElement != null ? ElementIterator.getAttributeTextContent(gaElement, A_ACCOUNT) : null;

        Element tabsElement = ElementIterator.getChildElement(element, T_TABS);
        List<Tab> tabList = new ArrayList<Tab>();
        int index = 0;
        for (ElementIterator i = new ElementIterator(tabsElement, T_TAB); index < 4 && i.hasNext(); ) {
            Element eTab = i.next();
            Tab tab = Tab.parse(eTab);
            if (tab != null) {
                tabList.add(tab);
                index++;
            }
        }
        if (tabList.isEmpty()) tabList = null;

        return new Config(ga, tabList);
    }

    private final String ga;
    private final List<Tab> tabList;

    Config(String ga, List<Tab> tabList) {
        this.ga = ga;
        this.tabList = tabList;
    }

    public List<Tab> getTabList() {
        return tabList;
    }

    public String getGa() {
        return ga;
    }

    static final class Contact {

        private static Contact parse(Element element) {
            if (element == null) return null;

            String address = ElementIterator.getChildTextContent(element, T_ADDRESS);

            List<Object> list = new ArrayList<Object>();
            for (ElementIterator i = new ElementIterator(element); i.hasNext(); ) {
                Element e = i.next();
                Object object = null;
                if (T_EMAIL.equalsIgnoreCase(e.getNodeName()))
                    object = Email.parse(e);
                else if (T_IMG.equalsIgnoreCase(e.getNodeName()))
                    object = Img.parse(e);
                else if (T_MAP.equalsIgnoreCase(e.getNodeName()))
                    object = Map.parse(e);
                else if (T_PHONE.equalsIgnoreCase(e.getNodeName()))
                    object = Phone.parse(e);
                if (object != null)
                    list.add(object);
            }
            if (list.isEmpty()) list = null;

            return new Contact(address, list);
        }

        private final String address;
        private final List<Object> list;

        Contact(String address, List<Object> list) {
            this.address = address;
            this.list = list;
        }

        public String getAddress() {
            return address;
        }

        public List<Object> getList() {
            return list;
        }
    }

    static final class ContactsTab extends Tab {

        private static Tab parse(Element element) {
            if (element == null) return null;

            String name = ElementIterator.getAttributeTextContent(element, A_NAME);
            String icon = ElementIterator.getAttributeTextContent(element, A_ICON);

            List<Group> groupList = new ArrayList<Group>();
            for (ElementIterator i = new ElementIterator(element, T_GROUP); i.hasNext(); ) {
                Element eGroup = i.next();
                Group group = Group.parse(eGroup);
                if (group != null) groupList.add(group);
            }
            if (groupList.isEmpty()) groupList = null;

            return new ContactsTab(name, icon, groupList);
        }

        private final List<Group> groupList;

        ContactsTab(String name, String icon, List<Group> groupList) {
            super(name, icon);
            this.groupList = groupList;
        }

        public List<Group> getGroupList() {
            return groupList;
        }
    }

    static final class Email {

        private static Email parse(Element element) {
            if (element == null) return null;

            String to = ElementIterator.getAttributeTextContent(element, A_TO);
            String cc = ElementIterator.getAttributeTextContent(element, A_CC);
            String subject = ElementIterator.getAttributeTextContent(element, A_SUBJECT);
            String text = ElementIterator.getAttributeTextContent(element, A_TEXT);
            String email = ElementIterator.getAttributeTextContent(element, A_EMAIL);

            return new Email(to, cc, subject, text, email);
        }

        private final String to;
        private final String cc;
        private final String subject;
        private final String text;
        private final String email;

        Email(String to, String cc, String subject, String text, String email) {
            this.to = to;
            this.cc = cc;
            this.subject = subject;
            this.text = text;
            this.email = email;
        }

        public String getTo() {
            return to;
        }

        public String getCc() {
            return cc;
        }

        public String getSubject() {
            return subject;
        }

        public String getText() {
            return text;
        }

        public String getEmail() {
            return email;
        }
    }

    static final class EmailTab extends Tab {

        private static Tab parse(Element element) {
            if (element == null) return null;

            String name = ElementIterator.getAttributeTextContent(element, A_NAME);
            String icon = ElementIterator.getAttributeTextContent(element, A_ICON);
            String login = ElementIterator.getAttributeTextContent(element, A_LOGIN);
            String pass = ElementIterator.getAttributeTextContent(element, A_PASS);
            String smtp = ElementIterator.getAttributeTextContent(element, A_SMTP);
            String html = ElementIterator.getChildTextContent(element, T_HTML);

            List<Email> emailList = new ArrayList<Email>();
            for (ElementIterator i = new ElementIterator(element, T_EMAIL); i.hasNext(); ) {
                Element eEmail = i.next();
                Email email = Email.parse(eEmail);
                if (email != null) emailList.add(email);
            }
            if (emailList.isEmpty()) emailList = null;

            return new EmailTab(name, icon, login, pass, smtp, emailList, html);
        }

        private final String login;
        private final String pass;
        private final String smtp;
        private final List<Email> emailList;
        private final String html;

        EmailTab(String name, String icon, String login, String pass, String smtp, List<Email> emailList, String html) {
            super(name, icon);
            this.login = login;
            this.pass = pass;
            this.smtp = smtp;
            this.emailList = emailList;
            this.html = html;
        }

        public String getLogin() {
            return login;
        }

        public String getPass() {
            return pass;
        }

        public String getSmtp() {
            return smtp;
        }

        public List<Email> getEmailList() {
            return emailList;
        }

        public String getHtml() {
            return html;
        }
    }

    static final class Feed {

        private static Feed parse(Element element) {
            if (element == null) return null;

            String name = ElementIterator.getAttributeTextContent(element, A_NAME);
            String url = ElementIterator.getAttributeTextContent(element, A_URL);

            return new Feed(name, url);
        }

        private final String name;
        private final String url;

        Feed(String name, String url) {
            this.name = name;
            this.url = url;
        }

        public String getName() {
            return name;
        }

        public String getUrl() {
            return url;
        }
    }

    static final class FeedsTab extends Tab {

        private static Tab parse(Element element) {
            if (element == null) return null;

            String name = ElementIterator.getAttributeTextContent(element, A_NAME);
            String icon = ElementIterator.getAttributeTextContent(element, A_ICON);
            String database = ElementIterator.getAttributeTextContent(element, A_DATABASE);

            if (database == null || database.trim().length() < 1)
                return null;

            List<Feed> feedList = new ArrayList<Feed>();
            for (ElementIterator i = new ElementIterator(element, T_FEED); i.hasNext(); ) {
                Element eFeed = i.next();
                Feed feed = Feed.parse(eFeed);
                if (feed != null) feedList.add(feed);
            }
            if (feedList.isEmpty()) feedList = null;

            return new FeedsTab(name, icon, database, feedList);
        }

        private final String database;
        private final List<Feed> feedList;

        FeedsTab(String name, String icon, String database, List<Feed> feedList) {
            super(name, icon);
            this.database = database;
            this.feedList = feedList;
        }

        public String getDatabase() {
            return database;
        }

        public List<Feed> getFeedList() {
            return feedList;
        }
    }

    static final class Group {

        private static Group parse(Element element) {
            if (element == null) return null;

            String name = ElementIterator.getAttributeTextContent(element, A_NAME);

            List<Contact> contactList = new ArrayList<Contact>();
            for (ElementIterator i = new ElementIterator(element, T_CONTACT); i.hasNext(); ) {
                Element eContact = i.next();
                Contact contact = Contact.parse(eContact);
                if (contact != null) contactList.add(contact);
            }
            if (contactList.isEmpty()) contactList = null;

            return new Group(name, contactList);
        }

        private final String name;
        private final List<Contact> contactList;

        Group(String name, List<Contact> contactList) {
            this.name = name;
            this.contactList = contactList;
        }

        public String getName() {
            return name;
        }

        public List<Contact> getContactList() {
            return contactList;
        }
    }

    static final class HtmlTab extends Tab {

        private static Tab parse(Element element) {
            if (element == null) return null;

            String name = ElementIterator.getAttributeTextContent(element, A_NAME);
            String icon = ElementIterator.getAttributeTextContent(element, A_ICON);
            String content = element.getTextContent();

            return new HtmlTab(name, icon, content);
        }

        private final String content;

        HtmlTab(String name, String icon, String content) {
            super(name, icon);
            this.content = content;
        }

        public String getContent() {
            return content;
        }
    }

    static final class Img {

        private static Img parse(Element element) {
            if (element == null) return null;

            String src = ElementIterator.getAttributeTextContent(element, A_SRC);

            return new Img(src);
        }

        private final String src;

        Img(String src) {
            this.src = src;
        }

        public String getSrc() {
            return src;
        }
    }

    static final class Map {

        private static Map parse(Element element) {
            if (element == null) return null;

            String text = ElementIterator.getAttributeTextContent(element, A_TEXT);
            String url = ElementIterator.getAttributeTextContent(element, A_URL);

            return new Map(text, url);
        }

        private final String text;
        private final String url;

        Map(String text, String url) {
            this.text = text;
            this.url = url;
        }

        public String getText() {
            return text;
        }

        public String getUrl() {
            return url;
        }
    }

    static final class Phone {

        private static Phone parse(Element element) {
            if (element == null) return null;

            String text = ElementIterator.getAttributeTextContent(element, A_TEXT);
            String number = ElementIterator.getAttributeTextContent(element, A_NUMBER);

            return new Phone(text, number);
        }

        private final String text;
        private final String number;

        Phone(String text, String number) {
            this.text = text;
            this.number = number;
        }

        public String getText() {
            return text;
        }

        public String getNumber() {
            return number;
        }
    }

    static abstract class Tab {

        private static Tab parse(Element element) {
            if (element == null) return null;

            String type = ElementIterator.getAttributeTextContent(element, A_TYPE);
            if (TAB_CONTACTS.equals(type))
                return ContactsTab.parse(element);
            if (TAB_EMAIL.equals(type))
                return EmailTab.parse(element);
            if (TAB_FEEDS.equals(type))
                return FeedsTab.parse(element);
            if (TAB_HTML.equals(type))
                return HtmlTab.parse(element);

            return null;
        }

        private final String name;
        private final String icon;

        Tab(String name, String icon) {
            this.name = name;
            this.icon = icon;
        }

        public String getName() {
            return name;
        }

        public String getIcon() {
            return icon;
        }
    }
}
